<script lang="ts">
    import {init, mergeFormValue, updateFormItem, validateForm} from "@/uni_modules/u-form/components/u-form/controls";
    import {formHandler, inputHandler, radioGroupHandler, checkboxGroupHandler, textareaHandler, switchHandler, sliderHandler} from "@/uni_modules/u-form/components/u-form/events";
    import mixin from "@/uni_modules/u-tools/mixin/mixin";
    import mpMixin from "@/uni_modules/u-tools/mixin/mpMixin";
    import props from "./props";
    import message from "./i18n/index";
    import {useI18n} from "vue-i18n";

    export default {
        name: "u-form",
        // 组件
        components: {},
        // 混合
        mixins: [props, mixin, mpMixin],
        // 事件
        emits: ["onload"],
        // 暴露方法
        expose: [
            "validate",
            "reset",
            "clearValidate",
            "fillForm",
            "updateSchema",
            "addSchema",
            "removeSchema",
            "setValue",
            "getValue"
        ],
        // 数据
        data()
        {
            return {
                // 表单项数据
                formList: <FormItemInterface[]>[],
                // 成功的表单字段
                successField: new Set()
            };
        },
        // 创建完毕
        setup()
        {
            const {t} = useI18n({
                locale: getStorage("language") || uni.getLocale(),
                messages: message
            });

            return {t};
        },
        // 监听器
        watch: {
            // 监听表单数据
            form: {
                handler(form: FormInterface[])
                {
                    // 每次组件变动重新初始化已加载的表单
                    this.successField.clear();

                    // 设置表单数据
                    this.formList = init(form, this.$props, this.t);

                    // 记录当前需要加载状态的表单项
                    this.formList.forEach((item: FormItemInterface) =>
                    {
                        if (item.type !== "custom")
                        {
                            this.successField.add(item.field);
                        }
                    });
                },
                immediate: true,
                deep: true
            }
        },
        // 方法
        methods: {
            // 表单验证
            validate(): Promise<Record<string, any>>
            {
                // 验证表单
                return validateForm(this.formList, this.t);
            },
            // 重置表单
            reset(): Promise<Record<string, any>>
            {
                return new Promise<Record<string, any>>(resolve =>
                {
                    // 设置表单数据
                    this.formList = init(this.form, this.$props, this.t);

                    resolve(mergeFormValue(this.formList));
                });
            },
            // 清除验证状态
            clearValidate(): void
            {
                this.formList.forEach((item: FormItemInterface) =>
                {
                    // 判断是否为自定义组件
                    if (item.type !== "custom")
                    {
                        item.validate = true;

                        item.message = "";
                    }
                });
            },
            // 回填表单
            fillForm(form: Record<string, any>): void
            {
                // 设置表单数据
                this.formList.each((item: FormItemInterface) =>
                {
                    // 当前的字段
                    const field = item.field;

                    // 当前回填的值
                    let value = form[field];

                    // 判断是否有值
                    if (value != null)
                    {
                        // 当前字段类型
                        const dataType = item.dataType;

                        // 判断数据类型
                        if (dataType === "number")
                        {
                            value = Number(value);
                        }
                        else if (dataType === "boolean")
                        {
                            value = Boolean(value);
                        }
                        else if (dataType === "array")
                        {
                            value = isArray(value) ? value : [];
                        }
                        else if (dataType === "object")
                        {
                            value = isObject(value) ? value : {};
                        }
                        else
                        {
                            value = String(value);
                        }
                    }

                    // 设置值
                    item.value = value;
                });
            },
            // 更新表单项
            updateSchema(form: FormInterface | FormInterface[]): Promise<Record<string, any>>
            {
                // 这里需要克隆表单原始数据，因为后面会修改表单数据，导致watch监听会触发多次
                return updateFormItem(form, clone(this.form, true), this.formList, this.$props, this.t, "update");
            },
            // 新增表单项
            addSchema(form: FormInterface | FormInterface[], position?: number | string, modifiers?: "before" | "after"): Promise<Record<string, any>>
            {
                // 这里需要克隆表单原始数据，因为后面会修改表单数据，导致watch监听会触发多次
                return updateFormItem(form, clone(this.form, true), this.formList, this.$props, this.t, "add", position, modifiers);
            },
            // 移出表单项
            removeSchema(field: string | string[]): Promise<Record<string, any>>
            {
                return new Promise<Record<string, any>>((resolve, reject) =>
                {
                    if (field)
                    {
                        if (isString(field))
                        {
                            field = [field];
                        }

                        if (field.length)
                        {
                            field.forEach((currentField: string) =>
                            {
                                this.formList.remove((item: FormItemInterface) =>
                                {
                                    return item.field === currentField;
                                });
                            });

                            resolve(mergeFormValue(this.formList));
                        }
                        else
                        {
                            reject({
                                message: this.t("form.removeSchemaEmpty")
                            });
                        }
                    }
                    else
                    {
                        reject({
                            message: this.t("form.removeSchemaEmpty")
                        });
                    }
                });
            },
            // 设置表单项的值
            setValue(formValue: Record<string, any>): Promise<Record<string, any>>
            {
                return new Promise<Record<string, any>>((resolve, reject) =>
                {
                    if (isObject(formValue) && !isEmpty(formValue))
                    {
                        for (const key in formValue)
                        {
                            // 判断当前字段是否存在于表单中
                            const currentForm = this.formList.find((item: FormItemInterface) =>
                            {
                                return item.field === key;
                            });

                            if (currentForm)
                            {
                                // 当前的值
                                let value = formValue[key];

                                // 判断是否有值
                                if (value != null)
                                {
                                    // 当前字段类型
                                    const dataType = currentForm.dataType;

                                    // 判断数据类型
                                    if (dataType === "number")
                                    {
                                        value = Number(value);
                                    }
                                    else if (dataType === "boolean")
                                    {
                                        value = Boolean(value);
                                    }
                                    else if (dataType === "array")
                                    {
                                        value = isArray(value) ? value : [];
                                    }
                                    else if (dataType === "object")
                                    {
                                        value = isObject(value) ? value : {};
                                    }
                                    else
                                    {
                                        value = String(value);
                                    }
                                }

                                // 设置值
                                currentForm.value = value;
                            }
                        }

                        resolve(mergeFormValue(this.formList));
                    }
                    else
                    {
                        reject({
                            message: this.t("form.setFieldValue")
                        });
                    }
                });
            },
            // 获取表单的值
            getValue(field?: string | string[]): Record<string, any>
            {
                // 如果没有传递指定的字段，则返回整个表单的值
                if (field)
                {
                    // 将参数转为数组
                    const currentFields: string[] = isArray(field) ? field : [field];

                    // 当前用作获取数据的表单项字段
                    const currentForm = this.formList.filter((item: FormItemInterface) =>
                    {
                        return currentFields.includes(item.field);
                    });

                    return mergeFormValue(currentForm);
                }
                else
                {
                    return mergeFormValue(this.formList);
                }
            },
            // 文本框事件
            ...inputHandler,
            // 文本域事件
            ...textareaHandler,
            // 单选组事件
            ...radioGroupHandler,
            // 多选组事件
            ...checkboxGroupHandler,
            // 开关事件
            ...switchHandler,
            // 滑块事件
            ...sliderHandler,
            // 表单组件事件
            ...formHandler
        }
    };
</script>

<template>
    <!-- 表单组件 -->
    <view
        :class="[customClass]"
        :style="[customStyle]"
        class="u-form"
    >
        <!-- 表单 -->
        <view
            :class="[
                'u-form-wrapper',
                `label-${labelAlign}`,
                `content-${contentAlign}`,
                placement,
                divider ? 'divider' : ''
            ]"
            :style="[
                {'--custom-form-line-spacing': $u.unit(spacing)}
            ]"
        >
            <!-- 遍历 -->
            <view
                v-for="item in formList"
                :key="item.field"
                :class="[
                    `content-placement-${item.placement}`,
                    {'hidden' : ['inputHidden'].includes(item.type) || !item.isShow}
                ]"
                class="item"
            >
                <!-- 容器 -->
                <view class="component-wrap">
                    <!-- 组件标题 -->
                    <view
                        :style="[
                            {width: placement === 'horizontal' ? $u.unit(labelWidth) : 'auto'}
                        ]"
                        class="label"
                    >
                        <u-text
                            :color="labelColor"
                            :font-family="labelFontFamily"
                            :font-size="labelFontSize"
                            :font-weight="labelFontWeight"
                            :prefix-text="item.required && labelAlign === 'right' ? '*' : ''"
                            :prefix-text-color="item.required && labelAlign === 'right' ? '#f00' : ''"
                            :suffix-text="item.required && labelAlign === 'left' ? '*' : ''"
                            :suffix-text-color="item.required && labelAlign === 'left' ? '#f00' : ''"
                            :text="item.label"
                            :type="labelType"
                        />
                    </view>
                    <!-- //组件标题 -->

                    <!-- 组件容器 -->
                    <view class="control">
                        <!-- 隐藏域 -->
                        <template v-if="['inputHidden'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-input
                                    :ref="item.field"
                                    v-model:value="item.value"
                                    :border="border"
                                    :disabled="disabled"
                                    :name="item.field"
                                    :output-type="item.dataType"
                                    :readonly="readonly"
                                    :size="size"
                                    :text-align="contentAlign"
                                    v-bind="item.componentProps"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->
                        </template>
                        <!-- //隐藏域 -->

                        <!-- 输入框 -->
                        <template v-if="['text', 'password', 'number', 'idcard', 'digit', 'tel'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-input
                                    :ref="item.field"
                                    v-model:value="item.value"
                                    :border="item.componentProps.border || border"
                                    :disabled="item.componentProps.disabled != null ? item.componentProps.disabled : disabled"
                                    :name="item.field"
                                    :output-type="item.dataType"
                                    :readonly="item.componentProps.readonly != null ? item.componentProps.readonly : readonly"
                                    :size="item.componentProps.size || size"
                                    :text-align="contentAlign"
                                    v-bind="item.componentProps"
                                    @blur="(value: string | number) => {inputBlurHandler({value: value, field: item.field, form: item})}"
                                    @confirm="(value: string | number) => {inputConfirmHandler({value: value, field: item.field, form: item})}"
                                    @focus="(value: string | number) => {inputFocusHandler({value: value, field: item.field, form: item})}"
                                    @input="(value: string | number) => {inputChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->

                            <!-- 自定义插槽 -->
                            <template v-if="item.field && $slots[item.field]">
                                <slot :name="item.field" />
                            </template>
                            <!-- //自定义插槽 -->
                        </template>
                        <!-- //输入框 -->

                        <!-- 文本域 -->
                        <template v-if="['textarea'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-textarea
                                    :ref="item.field"
                                    v-model:value="item.value"
                                    :border="item.componentProps.border || border"
                                    :disabled="item.componentProps.disabled != null ? item.componentProps.disabled : disabled"
                                    :font-size="size === 'mini' ? 12 : size === 'small' ? 14 : ''"
                                    :name="item.field"
                                    :readonly="item.componentProps.readonly != null ? item.componentProps.readonly : readonly"
                                    :text-align="contentAlign"
                                    v-bind="item.componentProps"
                                    @blur="(value: string | number) => {textareaBlurHandler({value: value, field: item.field, form: item})}"
                                    @confirm="(value: string | number) => {textareaConfirmHandler({value: value, field: item.field, form: item})}"
                                    @focus="(value: string | number) => {textareaFocusHandler({value: value, field: item.field, form: item})}"
                                    @input="(value: string | number) => {textareaChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->

                            <!-- 自定义插槽 -->
                            <template v-if="item.field && $slots[item.field]">
                                <slot :name="item.field" />
                            </template>
                            <!-- //自定义插槽 -->
                        </template>
                        <!-- //文本域 -->

                        <!-- 单选组 -->
                        <template v-if="['radioGroup'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-radio-group
                                    v-model:value="item.value"
                                    :content-align="contentAlign"
                                    :name="item.field"
                                    :options="item.componentProps.options || []"
                                    :padding="contentAlign === 'right' ? [8, 0, 8, 20] : [8, 20, 8, 0]"
                                    v-bind="item.componentProps"
                                    @change="(value: string | number) => {radioGroupChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->

                            <!-- 自定义插槽 -->
                            <template v-if="item.field && $slots[item.field]">
                                <slot :name="item.field" />
                            </template>
                            <!-- //自定义插槽 -->
                        </template>
                        <!-- //单选组 -->

                        <!-- 多选组 -->
                        <template v-if="['checkboxGroup'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-checkbox-group
                                    v-model:value="item.value"
                                    :content-align="contentAlign"
                                    :name="item.field"
                                    :options="item.componentProps.options || []"
                                    :padding="contentAlign === 'right' ? [8, 0, 8, 20] : [8, 20, 8, 0]"
                                    v-bind="item.componentProps"
                                    @change="(value: string | number) => {checkboxGroupChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->

                            <!-- 自定义插槽 -->
                            <template v-if="item.field && $slots[item.field]">
                                <slot :name="item.field" />
                            </template>
                            <!-- //自定义插槽 -->
                        </template>
                        <!-- //多选组 -->

                        <!-- 开关 -->
                        <template v-if="['switch'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-switch
                                    v-model:value="item.value"
                                    :name="item.field"
                                    :custom-style="{margin: '4px 0'}"
                                    v-bind="item.componentProps"
                                    @change="(value: string | number) => {switchChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->

                            <!-- 自定义插槽 -->
                            <template v-if="item.field && $slots[item.field]">
                                <slot :name="item.field" />
                            </template>
                            <!-- //自定义插槽 -->
                        </template>
                        <!-- //开关 -->

                        <!-- 滑块 -->
                        <template v-if="['slider'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <u-slider
                                    v-model:value="item.value"
                                    :name="item.field"
                                    v-bind="item.componentProps"
                                    @change="(value: string | number) => {sliderChangeHandler({value: value, field: item.field, form: item, t})}"
                                    @onload="() => {onloadHandler({field: item.field, form: item})}"
                                />
                            </view>
                            <!-- //控件区域 -->
                        </template>
                        <!-- //滑块 -->

                        <!-- 自定义插槽 -->
                        <template v-if="['custom'].includes(item.type)">
                            <!-- 控件区域 -->
                            <view :class="['component', `component-${item.type}`]">
                                <slot :name="item.field" />
                            </view>
                            <!-- //控件区域 -->
                        </template>
                        <!-- //自定义插槽 -->
                    </view>
                    <!-- //组件容器 -->
                </view>
                <!-- //容器 -->

                <!-- 错误信息 -->
                <view
                    v-if="!item.validate && item.message"
                    :style="{marginLeft: placement === 'vertical' ? 0 : $u.unit(labelWidth)}"
                >
                    <u-text
                        :font-size="12"
                        :line-height="20"
                        :text="item.message"
                        color="#fe4a41"
                    />
                </view>
                <!-- //错误信息 -->
            </view>
            <!-- //遍历 -->
        </view>
        <!-- //表单 -->
    </view>
    <!-- //表单组件 -->
</template>

<style lang="scss" scoped>
    .u-form
    {
        // 表单
        .u-form-wrapper
        {
            // 表单项
            .item
            {
                display: flex;
                flex-direction: column;

                // 容器
                .component-wrap
                {
                    display: flex;

                    // 组件容器
                    .control
                    {
                        display: flex;
                        align-items: center;
                        flex: 1;

                        // 控件区域
                        .component
                        {
                            flex: 1;

                            // 开关
                            &.component-switch
                            {
                                display: flex;
                            }
                        }
                    }

                    // 控件与插槽的横向对齐
                    &.content-placement-horizontal
                    {
                        // 组件容器
                        .control
                        {
                            flex-direction: row;
                        }
                    }

                    // 控件与插槽的纵向对齐
                    &.content-placement-vertical
                    {
                        // 组件容器
                        .control
                        {
                            align-items: stretch;
                            flex-direction: column;
                        }
                    }
                }

                // 隐藏表单
                &.hidden
                {
                    display: none;
                }
            }

            // 横向布局
            &.horizontal
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        // 标题
                        .label
                        {
                            display: flex;
                            align-items: center;

                            &:after
                            {
                                margin: 0 4px 0 2px;
                                content: "";
                            }
                        }
                    }

                    &:not(:first-child)
                    {
                        padding: var(--custom-form-line-spacing) 0;
                    }
                }
            }

            // 纵向布局
            &.vertical
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        flex-direction: column;

                        // 组件容器
                        .control
                        {
                            margin-top: 6px;
                        }
                    }

                    &:not(:first-child)
                    {
                        padding: var(--custom-form-line-spacing) 0;
                    }
                }
            }

            // 内容左对齐
            &.content-left
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        // 组件容器
                        .control
                        {
                            // 控件区域
                            .component
                            {
                                // 开关
                                &.component-switch
                                {
                                    justify-content: flex-start;
                                }
                            }
                        }
                    }
                }
            }

            // 内容右对齐
            &.content-right
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        // 组件容器
                        .control
                        {
                            // 控件区域
                            .component
                            {
                                // 开关
                                &.component-switch
                                {
                                    justify-content: flex-end;
                                }
                            }
                        }
                    }
                }
            }

            // 表单分割线
            &.divider
            {
                // 表单项
                .item
                {
                    border-bottom: 1px solid #eaeaeb;
                }
            }

            // 标签左对齐
            &.label-left
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        // 标签
                        .label
                        {
                            justify-content: flex-start;
                        }
                    }
                }
            }

            // 标签右对齐
            &.label-right
            {
                // 表单项
                .item
                {
                    // 容器
                    .component-wrap
                    {
                        // 标签
                        .label
                        {
                            justify-content: flex-end;
                        }
                    }
                }
            }
        }
    }
</style>